﻿namespace 委托_事件_Action
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            //委托delegate，类似于c中的函数指针，其主要作用为把方法当作参数传递
            int a, b, c, d;
            MyDelegate md;
            md = Add;//将委托指向Add方法
            a = md(10, 20);
            Console.WriteLine(a);
            b = Test(md);//将委托当作参数传递
            Console.WriteLine(b);

            md = Reduce;//将委托指向Reduce方法
            c = md(10, 20);
            Console.WriteLine(c);
            d = Test(md);
            Console.WriteLine(d);

            //利用委托实现简单的发布/订阅模式，即观察者模式
            MyDelegate2 md2 = null;
            md2 += cw1;
            md2 += cw2;
            md2(3);
            //注意：如果此时使用md=cw2重新赋值，那么委托会将所有的订阅取消，只保留最后一个赋值
            var instance = new Demo();
            instance.emd += (sender, arg) =>
            {
                Console.WriteLine("执行事件1");
            };
            instance.emd += (sender, arg) =>
            {
                Console.WriteLine("执行事件2");
            };
            instance.RaiseEvent();
            //事件异常：每个事件订阅者必须处理好自己的异常，不能抛出来，当某个事件订阅者触发抛出异常后，后面的订阅者的事件都不会执行
            //事件异步：异步事件不会阻塞进程，可以与普通异步一样使用

            //Func代表有返回值的委托，Action代表无返回值的委托
            Func<int, int, int> md3;
            md3 = (x, y) => x + y;
            a = md3(10, 20);
            Console.WriteLine(a);
            b = Test(md3);
            Console.WriteLine(b);

            md3 = (x, y) => x - y;
            c = md3(10, 20);
            Console.WriteLine(c);
            d = Test(md3);
            Console.WriteLine(d);
        }

        //定义委托
        public delegate int MyDelegate(int x, int y);

        public delegate void MyDelegate2(int x);

        //定义事件,利用委托来定义事件
        public event MyDelegate2 emd;

        //利用EventHandler来定义事件
        public event EventHandler emd2;

        public static void cw1(int x)
        {
            Console.WriteLine(x);
        }

        public static void cw2(int x)
        {
            Console.WriteLine(x);
        }

        //与委托匹配的方法
        public static int Add(int a, int b)
        {
            return a + b;
        }

        //与委托匹配的另一个方法
        public static int Reduce(int a, int b)
        {
            return a - b;
        }

        //将委托当作参数传递
        public static int Test(MyDelegate md)
        {
            return md(20, 20);
        }

        //利用Func来使用委托
        public static int Test(Func<int, int, int> md)
        {
            return md(20, 20);
        }
    }

    //事件使用
    public class Demo
    {
        public event EventHandler emd;

        public void RaiseEvent()
        {
            emd(this, EventArgs.Empty);
        }
    }
}